{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "参考：https://blog.csdn.net/len9596/article/details/79990823"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 作用域\n",
    "\n",
    "在python中，作用域分为两种:全局作用域和局部作用域。\n",
    "\n",
    "**全局作用域**是定义在文件级别的变量, 函数名。而**局部作用域**，则是定义函数内部。\n",
    "\n",
    "关于作用域，我们要理解：\n",
    "\n",
    "- a.在全局不能访问到局部定义的变量\n",
    "\n",
    "- b.在局部能够访问到全局定义的变量，但是不能对全局变量重新赋值；\n",
    "\n",
    "- 可变类型的全局变量可以在局部代码块被修改\n",
    "\n",
    "下面我们来看看下面实例:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "x = 1\n",
    "def funx():\n",
    "    x = 10\n",
    "    print(x)  # 打印出10\n",
    "\n",
    "funx()\n",
    "print(x) # 打印出1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br>\n",
    "如果局部没有定义变量x,那么函数内部会从内往外开始查找x,如果没有找到,就会报错"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "x = 1\n",
    "def funx():\n",
    "    print(x)  \n",
    "\n",
    "funx()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "x = 1\n",
    "def funx():\n",
    "    def func1():\n",
    "        print(x)  \n",
    "    func1()\n",
    "\n",
    "funx()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'a': 1}\n",
      "{'a': 1}\n"
     ]
    }
   ],
   "source": [
    "x = {}\n",
    "\n",
    "def foo():\n",
    "    x.update({'a': 1})\n",
    "    print(x)\n",
    "\n",
    "foo()\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "因此,关于作用域的问题，只需要记住两点就行:\n",
    "\n",
    "全局变量能够被文件任何地方引用，但修改只能在全局进行操作;如果局部没有找到所需的变量，就会往外进行查找，没有找到就会报错."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 高阶函数（略）\n",
    "\n",
    "**python 中一切皆对象**\n",
    "\n",
    "- 函数名可以作为一个值\n",
    "- 函数名可以作为返回值 \n",
    "- 函数名可以作为一个参数\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 闭包函数\n",
    "\n",
    "闭包函数必须满足两个条件:\n",
    "\n",
    "1. 函数内部定义的函数 \n",
    "2. 包含对外部作用域而非全局作用域的引用\n",
    "\n",
    "下面通过一些实例来说明闭包函数:\n",
    "\n",
    "**实例一:** 以下仅仅在函数内部定义了一个函数,但并非闭包函数."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "inner func excuted\n",
      "outer func excuted\n"
     ]
    }
   ],
   "source": [
    "def outer():\n",
    "    def inner():\n",
    "        print(\"inner func excuted\")\n",
    "    inner()  # 调用执行inner()函数\n",
    "    print(\"outer func excuted\")\n",
    "outer()  # 调用执行outer函数\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**实例二** :以下在函数内部定义了一个函数，而且还引用了一个外部变量x,那么这个是闭包函数么?答案：不是"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x=1\n",
      "inner func excuted\n",
      "outer func excuted\n"
     ]
    }
   ],
   "source": [
    "x = 1\n",
    "\n",
    "def outer():\n",
    "    def inner():\n",
    "        print(\"x=%s\" %x)  # 引用了一个非inner函数内部的变量\n",
    "        print(\"inner func excuted\")\n",
    "    inner()  # 执行inner函数\n",
    "    print(\"outer func excuted\")\n",
    "\n",
    "outer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在回头来看看对闭包函数的定义，是不是两条都满足?聪明的你，一定发现不满足第二条.对，这里的变量x，是属于全局变量,而非外部作用于域的变量。再来看看下面例子:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x=1\n",
      "inner func excuted\n",
      "outer func excuted\n"
     ]
    }
   ],
   "source": [
    "def outer():\n",
    "    x = 1\n",
    "    def inner():\n",
    "        print(\"x=%s\" %x)\n",
    "        print(\"inner func excuted\")\n",
    "    inner()\n",
    "    print(\"outer func excuted\")\n",
    "\n",
    "outer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "显然,上面实例满足闭包函数的条件。现在，你应该清楚,作为一个闭包函数,必须得满足上述的两个条件,缺一不可。但是,一般情况下，我们都会给闭包函数返回一个值.这里先不说为什么.在接下来的内容中，你会看到这个返回值的用途."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "outer func excuted\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<function __main__.outer.<locals>.inner()>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def outer():\n",
    "    x = 1\n",
    "    def inner():\n",
    "        print(\"x=%s\" %x)\n",
    "        print(\"inner func excuted\")\n",
    "    print(\"outer func excuted\")\n",
    "    return inner  # 返回内部函数名\n",
    "    \n",
    "outer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们来抽象的定义一下闭包函数。它是函数和与其相关的引用环境组合而成的实体。在实现深约束时，需要创建一个能显式表示引用环境的东西，并将它与相关的子程序捆绑在一起，这样捆绑起成为闭包。在上面实例中，我们可以发现,闭包函数,它必须包含自己的函数以及一个外部变量才能真正称得上是一个闭包函数。如果没有一个外部变量与其绑定,那么這个函数不能算得上是闭包函数。\n",
    "\n",
    "　　那么怎么知道一个闭包函数有多少个外部引用变量呢?看看下面代码."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(<cell at 0x000001FBC78D2DF8: int object at 0x00007FFF5EAD9340>, <cell at 0x000001FBC78D2948: int object at 0x00007FFF5EAD9360>)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<function __main__.outer.<locals>.inner()>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def outer():\n",
    "    x = 1\n",
    "    y = 2\n",
    "\n",
    "    def inner():\n",
    "        print(\"x= %s\" %x)\n",
    "        print(\"y= %s\" %y)\n",
    "\n",
    "    print(inner.__closure__)\n",
    "    return inner\n",
    "\n",
    "outer()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "结果表明,在inner内部，引用了两个外部局部变量。如果引用的是非局部变量，那么这里输出的为None.\n",
    "\n",
    "闭包函数的特点：\n",
    "\n",
    "1. 自带作用域 \n",
    "2. 延迟计算\n",
    "\n",
    "　　那么闭包函数有什么作用呢?我们清楚的知道，闭包函数在定义时，一定会绑定一个外部环境。這个整体才能算的上是一个闭包函数，那么我们可以利用这个绑定特性，来完成某些特殊的功能。\n",
    "  \n",
    "**实例三**：根据传入的URL,来下载页面源码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<Response [200]>\n",
      "<Response [200]>\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "def index(url):\n",
    "    def get():\n",
    "        return requests.get(url)\n",
    "    return get\n",
    "\n",
    "python = index(\"https://www.python.org\") # 返回的是get函数的地址\n",
    "print(python()) # 执行get函数《并且将返回的结果打印出来\n",
    "baidu = index(\"https://www.baidu.com\")\n",
    "print(baidu())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有人可以会说,这个不满足闭包函数的条件啊!我没有引用非全局的外部变量啊。其实并非如此,给，我们之前说过,**只要在函数内部的变量都属于函数。那么我在index(url)，这个url也属于函数内部，**只不过我们省略一步而已，所以上面那个函数也是闭包函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 装饰器\n",
    "\n",
    "装饰器：外部函数传入被装饰函数名，内部函数返回装饰函数名。\n",
    "\n",
    "特点：\n",
    "1. 不修改被装饰函数的调用方式 \n",
    "2. 不修改被装饰函数的源代码\n",
    "\n",
    "## 简单装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:bar is running\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I am bar\n",
      "wrapper\n",
      "测试\n"
     ]
    }
   ],
   "source": [
    "import logging\n",
    "\n",
    "def use_logging(func):\n",
    "    def wrapper(*args,**kwargs):\n",
    "        logging.warning(\"%s is running\"% func.__name__)\n",
    "        return func(*args,**kwargs)\n",
    "    wrapper.__doc__ = func.__doc__\n",
    "    return wrapper\n",
    "\n",
    "\n",
    "def bar():\n",
    "    \"\"\"测试\"\"\"\n",
    "    print('I am bar')\n",
    "\n",
    "bar = use_logging(bar)\n",
    "bar()\n",
    "print(bar.__name__)\n",
    "print(bar.__doc__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 划重点\n",
    "\n",
    "函数use_logging就是装饰器，它把执行真正业务方法的func包裹在函数里面，看起来像bar被use_logging装饰了。在这个例子中，函数进入和退出时 ，被称为一个**横切面(Aspect)**，这种编程方式被称为**面向切面的编程(Aspect-Oriented Programming)。**\n",
    "\n",
    "@符号可以理解为避免再一次赋值操作的 **简写** \n",
    "\n",
    "```\n",
    "@ 等价于 a = d(a)\n",
    "```\n",
    "\n",
    "这样我们就可以省去bar = use_logging(bar)这一句了，直接调用bar()即可得到想要的结果。\n",
    "\n",
    "注意：\n",
    "1. 原函数的一些元属性会丢失，比如: 文档字符串`__doc__`，需要重新赋值给内部函数。\n",
    "\n",
    "2. 参数要通过`(*args,**kwargs)` 全部传递过去。\n",
    "\n",
    "3. 内部函数的返回值，是对被装饰函数简单调用就结束，还是需要 `return` 其返回值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:bar is running\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "param is: 3\n",
      "I am bar\n",
      "wrapper\n"
     ]
    }
   ],
   "source": [
    "@use_logging\n",
    "def bar(param=2):\n",
    "    print('param is: {}'.format(param))\n",
    "    return 'I am bar'\n",
    "\n",
    "\n",
    "print(bar(param=3))\n",
    "print(bar.__name__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 有参数装饰器\n",
    "\n",
    "在上面的装饰器调用中，比如@use_logging，该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时，提供其它参数，比如\n",
    "```\n",
    "@decorator(a)\n",
    "```\n",
    "这样，就为装饰器的编写和使用提供了更大的灵活性。\n",
    "\n",
    "在`decorator(a)`阶段 ,就已经发生了一次函数调用，并返回了像上面所说的简单装饰器函数use_logging，所以`decorator` 函数具体实现方法，就是在简单装饰器上再包装一层函数，将简单装饰器作为返回值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:foo is running\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I am bar\n"
     ]
    }
   ],
   "source": [
    "import logging\n",
    "\n",
    "\n",
    "def use_logging(level):\n",
    "    def decorator(func):\n",
    "        def wrapper(*args, **kwargs):\n",
    "            if level == \"warn\":\n",
    "                logging.warning(\"%s is running\" % func.__name__)\n",
    "            return func(*args, **kwargs)\n",
    "\n",
    "        return wrapper\n",
    "\n",
    "    return decorator\n",
    "\n",
    "\n",
    "def foo(name='foo'):\n",
    "    print('I am bar')\n",
    "\n",
    "\n",
    "# 不用@ 符号写法\n",
    "foo = use_logging('warn')(foo)\n",
    "foo()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:foo is running\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I am bar\n",
      "wrapper\n"
     ]
    }
   ],
   "source": [
    "@use_logging(\"warn\")\n",
    "def foo(name='foo'):\n",
    "    print('I am bar')\n",
    "\n",
    "foo()\n",
    "print(foo.__name__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 类装饰器\n",
    "\n",
    "相比函数装饰器，类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的`__call__`方法，当使用 @ 形式将装饰器附加到函数上时，就会调用此方法。\n",
    "\n",
    "**实例一：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "code_folding": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "class decorator runing\n",
      "bar\n",
      "class decorator ending\n"
     ]
    }
   ],
   "source": [
    "class Foo(object):\n",
    "    def __init__(self, func):\n",
    "        self._func = func\n",
    "        self.__doc__ = func.__doc__\n",
    "\n",
    "    def __call__(self):\n",
    "        print('class decorator runing')\n",
    "        result = self._func()\n",
    "        print('class decorator ending')\n",
    "        return result\n",
    "\n",
    "\n",
    "@Foo\n",
    "def bar():\n",
    "    \"\"\"test doc\"\"\"\n",
    "    print('bar')\n",
    "\n",
    "\n",
    "bar()\n",
    "# print(bar.__doc__)\n",
    "# print(bar.__class__.__name__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同样的，原函数的元信息不见了，比如函数的docstring、name、参数列表，需要手动传递进去。\n",
    "\n",
    "**实例二**："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "class decorator runing\n",
      "bar\n"
     ]
    }
   ],
   "source": [
    "class Foo(object):\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    def __call__(self, func):\n",
    "        def _call(*args, **kw):\n",
    "            print('class decorator runing')\n",
    "            return func(*args, **kw)\n",
    "\n",
    "        return _call\n",
    "\n",
    "\n",
    "class Bar(object):\n",
    "    @Foo()\n",
    "    def bar(self, test, ids):   # bar = Foo()(bar)\n",
    "        print('bar')\n",
    "\n",
    "\n",
    "Bar().bar('aa', 'ids')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true
   },
   "source": [
    "## 内置装饰器\n",
    "\n",
    "- @staticmathod\n",
    "- @classmethod\n",
    "- @property"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 装饰器的运行顺序: 从下往上\n",
    "```py\n",
    "@a\n",
    "@b\n",
    "@c\n",
    "def f ():\n",
    "```\n",
    "等效于\n",
    "\n",
    "```py\n",
    "f = a(b(c(f)))\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name: egon\n",
      "password: 123\n",
      "login successful\n",
      "welecome to index page\n",
      "run time is 3.0001261234283447\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "import random\n",
    "\n",
    "\n",
    "def timmer(func):\n",
    "    def wrapper():\n",
    "        start_time = time.time()\n",
    "        func()\n",
    "        stop_time = time.time()\n",
    "        print('run time is %s' % (stop_time - start_time))\n",
    "\n",
    "    return wrapper\n",
    "\n",
    "\n",
    "def auth(func):\n",
    "    def deco():\n",
    "        name = input('name: ')\n",
    "        password = input('password: ')\n",
    "        if name == 'egon' and password == '123':\n",
    "            print('login successful')\n",
    "            func()  #wrapper()\n",
    "        else:\n",
    "            print('login err')\n",
    "\n",
    "    return deco\n",
    "\n",
    "\n",
    "@auth  # index = auth(timmer(index))\n",
    "@timmer  # index = timmer(index)\n",
    "def index():\n",
    "    time.sleep(3)\n",
    "    print('welecome to index page')\n",
    "\n",
    "\n",
    "index()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 实战用例\n",
    "\n",
    "## 限制执行间隔不低于5s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step1: 16:57:35\n",
      "step2:  16:57:37\n",
      "finally execute:  16:57:37\n",
      "fuction end: 16:57:37\n",
      "warpper return:  16:57:40\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "from datetime import datetime\n",
    "\n",
    "\n",
    "def interval_execute(interval: int = 5):\n",
    "    \"\"\"执行时间\"\"\"\n",
    "\n",
    "    def timer(func):\n",
    "        def inner(*args, **kwargs):\n",
    "            start = time.time()\n",
    "            result = func(*args, **kwargs)\n",
    "            print('fuction end:', datetime.now().strftime('%H:%M:%S'))\n",
    "            end = time.time()\n",
    "            # 间隔\n",
    "            if end - start < interval:\n",
    "                time.sleep(interval - (end - start))\n",
    "            print('warpper return: ', datetime.now().strftime('%H:%M:%S'))\n",
    "            return result\n",
    "\n",
    "        return inner\n",
    "\n",
    "    return timer\n",
    "\n",
    "\n",
    "@interval_execute(5)\n",
    "def foo():\n",
    "    try:\n",
    "        print('step1:', datetime.now().strftime('%H:%M:%S'))\n",
    "        time.sleep(2)\n",
    "        print('step2: ', datetime.now().strftime('%H:%M:%S'))\n",
    "        return 123\n",
    "    finally:\n",
    "        print('finally execute: ', datetime.now().strftime('%H:%M:%S'))\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    foo()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 限制总执行时间\n",
    "\n",
    "```sh\n",
    "pip install func_timeout\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "from func_timeout import func_set_timeout\n",
    "import time\n",
    "\n",
    "@func_set_timeout(3)\n",
    "def foo(wait_seconds=2):\n",
    "    print('开始执行')\n",
    "    time.sleep(wait_seconds)\n",
    "    print('正常结束')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始执行\n",
      "正常结束\n"
     ]
    }
   ],
   "source": [
    "foo(2.99)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始执行\n"
     ]
    },
    {
     "ename": "FunctionTimedOut",
     "evalue": "Function foo (args=(3.1,)) (kwargs={}) timed out after 3.000000 seconds.\n",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mFunctionTimedOut\u001b[0m                          Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-21-656f3b4cc01b>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mfoo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m3.1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32mD:\\SoftInstall\\Anacoda3\\lib\\site-packages\\func_timeout\\dafunc.py\u001b[0m in \u001b[0;36m<lambda>\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m    183\u001b[0m         \u001b[1;32mdef\u001b[0m \u001b[0m_function_decorator\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfunc\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    184\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 185\u001b[1;33m             \u001b[1;32mreturn\u001b[0m \u001b[0mwraps\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfunc\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m \u001b[1;33m:\u001b[0m \u001b[0mfunc_timeout\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdefaultTimeout\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    186\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    187\u001b[0m \u001b[1;31m#            def _function_wrapper(*args, **kwargs):\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\SoftInstall\\Anacoda3\\lib\\site-packages\\func_timeout\\dafunc.py\u001b[0m in \u001b[0;36mfunc_timeout\u001b[1;34m(timeout, func, args, kwargs)\u001b[0m\n\u001b[0;32m     99\u001b[0m         \u001b[0mthread\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_stopThread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstopException\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    100\u001b[0m         \u001b[0mthread\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m.1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m \u001b[1;33m/\u001b[0m \u001b[1;36m50.0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 101\u001b[1;33m         \u001b[1;32mraise\u001b[0m \u001b[0mFunctionTimedOut\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m''\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    102\u001b[0m     \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    103\u001b[0m         \u001b[1;31m# We can still cleanup the thread here..\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mFunctionTimedOut\u001b[0m: Function foo (args=(3.1,)) (kwargs={}) timed out after 3.000000 seconds.\n"
     ]
    }
   ],
   "source": [
    "foo(3.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 额外添加异常信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "error in class - [name: DOG]\n"
     ]
    }
   ],
   "source": [
    "def add_more_exception_info(**info):\n",
    "    \"\"\"抛出异常时，为异常实例提供额外的异常信息\"\"\"\n",
    "\n",
    "    def add_info(f):\n",
    "        def warrper(*args, **kwargs):\n",
    "            try:\n",
    "                result = f(*args, **kwargs)\n",
    "                return result\n",
    "            except Exception as e:\n",
    "                e.__dict__.update(info)\n",
    "                raise e\n",
    "\n",
    "        return warrper\n",
    "\n",
    "    return add_info\n",
    "\n",
    "\n",
    "class Foo:\n",
    "    name = 'DOG'\n",
    "    \n",
    "    @add_more_exception_info(task_name=name)\n",
    "    def test(self):\n",
    "        1/0\n",
    "\n",
    "try:\n",
    "    Foo().test()\n",
    "except Exception as e:\n",
    "    print('error in class - [name: {}]'.format(e.task_name))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
